﻿using System;
using System.ComponentModel;
using System.Drawing.Design;
using System.Reflection;

namespace UtfprLibrary.Windows.Forms.ComponentModel {
    /// <summary>
    /// TODO
    /// O editor DataMemberFieldEditor procuraria uma propriedade DataSource, 
    /// mas utilizei um customizado (LookupMemberFieldEditor), que busca o LookupSource
    /// </summary>
    internal class UtfprLookupSourceDataMemberFieldEditor : UITypeEditor {
        #region Properties

        private Type _designBindingPickerType;
        /// <summary>
        /// Gets the type of the design binding picker.
        /// </summary>
        /// <value>The type of the design binding picker.</value>
        private Type DesignBindingPickerType {
            get {
                if (_designBindingPickerType == null) {
                    _designBindingPickerType = Type.GetType("System.Windows.Forms.Design.DesignBindingPicker, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                }
                return _designBindingPickerType;
            }
        }

        private Type _designBindingType;
        /// <summary>
        /// Gets the type of the design binding.
        /// </summary>
        /// <value>The type of the design binding.</value>
        private Type DesignBindingType {
            get {
                if (_designBindingType == null) {
                    _designBindingType = Type.GetType("System.Windows.Forms.Design.DesignBinding, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
                }
                return _designBindingType;
            }
        }

        private object _designBindingPicker;
        /// <summary>
        /// TODO
        /// </summary>
        private object DesignBindingPicker {
            get {
                if (_designBindingPicker == null) {
                    _designBindingPicker = Activator.CreateInstance(DesignBindingPickerType, true);
                }
                return _designBindingPicker;
            }
        }


        #endregion

        #region Override Methods

        /// <summary>
        /// Gets a value indicating whether drop-down editors should be resizable by the user.
        /// </summary>
        /// <value></value>
        /// <returns>true if drop-down editors are resizable; otherwise, false.
        /// </returns>
        public override bool IsDropDownResizable {
            get {
                return true;
            }
        }

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
            if (provider != null && context.Instance != null) {
                PropertyDescriptor lookupSourceProperty = TypeDescriptor.GetProperties(context.Instance)["LookupSource"];

                if (lookupSourceProperty != null) {
                    object lookupSource = lookupSourceProperty.GetValue(context.Instance);
                    object oldSelection = Activator.CreateInstance(DesignBindingType, new object[] { lookupSource, (string)value });
                    object newSelection = InvokePickMethodFromDesignBindingPicker(context, provider, lookupSource, oldSelection);

                    if (lookupSource != null && newSelection != null) {
                        value = newSelection.GetType().GetProperty("DataMember").GetValue(newSelection, null);
                    }
                }
            }

            return value;
        }

        /// <summary>
        /// Gets the editor style used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"/> method.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that can be used to gain additional context information.</param>
        /// <returns>
        /// A <see cref="T:System.Drawing.Design.UITypeEditorEditStyle"/> value that indicates the style of editor used by the <see cref="M:System.Drawing.Design.UITypeEditor.EditValue(System.IServiceProvider,System.Object)"/> method. If the <see cref="T:System.Drawing.Design.UITypeEditor"/> does not support this method, then <see cref="M:System.Drawing.Design.UITypeEditor.GetEditStyle"/> will return <see cref="F:System.Drawing.Design.UITypeEditorEditStyle.None"/>.
        /// </returns>
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
            return UITypeEditorEditStyle.DropDown;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// TODO
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="lookupSource"></param>
        /// <param name="oldSelection"></param>
        /// <returns></returns>
        private object InvokePickMethodFromDesignBindingPicker(ITypeDescriptorContext context, IServiceProvider provider, object lookupSource, object oldSelection) {
            var flags = BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public;
            var args = new object[] { 
                        context, provider, 
                        false, /* showDataSources   */
                        true,  /* showDataMembers   */
                        false, /* selectListMembers */
                        lookupSource, String.Empty, oldSelection };

            return DesignBindingPickerType.InvokeMember("Pick", flags, null, DesignBindingPicker, args);
        }

        #endregion
    }
}
